package Client;
use strict;
use warnings;
use utf8;

use EV;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(
parse_input
long_connection
ts
get_param
process_response
input_handler
interval_handler
signal_handler
login_handler
run_interval
);

use Getopt::Long;

sub after_join {
	if($main::run){
		my @run = split /\s*\|\s*/,$main::run;
		@main::run = @run;
	}else{
		@main::run = ();
	}
	run_handler();
}
sub run_handler {
	if(my $str = shift @main::run){
		my($cmd,$msg) = parse_input($str);
		if($cmd){
			main::send_message($cmd,$msg,\&run_handler);
		}else{
			main::send_message("message",{text=>$str||""},\&run_handler);
		}
	}else{
		main::after_start();
	}
}
sub login_handler {
	my $msg = shift;
	unless($msg->{error}){
		$main::sid = $msg->{sid};
		main::run_checker();
		main::send_message(create=>{chanel=>$main::chanel},sub {
			main::send_message(join=>{chanel=>$main::chanel},\&after_join);
		});
	}else{
		print "Cannot login '$msg->{error}' '$msg->{text}'\n";
		EV::break EV::BREAK_ALL;
	}
}
sub input_handler {
	my $str = <STDIN>;
	my ($cmd,$msg) = parse_input($str);
	if($cmd){
		main::send_message($cmd,$msg);
	}else{
		print "<internal>",$msg,"\n" if $msg;
	}
}
my $interval_watcher;
my $interval_to;
sub run_interval {
	$interval_to = shift;
	$interval_watcher = EV::periodic time() + $interval_to, $interval_to, 0, \&interval_handler;
}
sub reset_interval {
	$interval_watcher->set(time() + $interval_to,$interval_to,0);
}
sub interval_handler {
	if(++$main::count < $main::maxcount){
		main::send_message(message=>{text =>"my counter ".$main::count." from ".$main::maxcount." ".ts(),chanel=>$main::chanel},\&reset_interval);
	}else{
		EV::break EV::BREAK_ALL;
	}
}
sub signal_handler {
	print "\nSIGINT, will now quit\n";
	EV::break EV::BREAK_ALL;
}

sub parse_input{
	my $str = shift;
	chomp $str;
	my $cmd;
	my $msg;
	if($str =~ /^\s*private\s*\[([^\]]*)\]/){
		$msg->{text} = $str;
		if(my @list = grep {$_} map {s/^\s+//;s/\s+$//;$_} split /,/, $1){
			push @list,$main::login;
			$msg->{to} = \@list;
			$cmd = "private";
		}else{
			$cmd = "message";
		}
	}
	elsif($str =~ s/^\s*!//){
		if($str =~ s|^\s*/||){
			if($str =~ s/(\w+)\s*(\w+)//){
				$cmd = $1;
				$msg->{chanel} = $2;
			}else{
				$msg = "bad format: !/$str";
			}
		}
		elsif($str =~ s/(\w+)\s*//){
			$cmd = "message";
			$msg->{chanel} = $1;
			$msg->{text} = $str;
		}
		else{
			$msg = "bad format: !$str";
		}
	}
	elsif($str =~ s|^\s*/\s*||){
		if($str =~/^(dstart|dstop|sstop|stat)(?:\s+(\w+))?(?:\s+(\w+))?/){
			$cmd = "command";
			$msg->{param1} = $1 if $1;
			$msg->{param2} = $2 if $2;
			$msg->{param3} = $3 if $3;
		}
		elsif($str =~ /^exit/){
			EV::break EV::BREAK_ALL;
			$msg = "exited";
		}
		elsif($str =~ /^((?:un)?reg)\s+(\w+)(?:\s+(\w+))?/){
			$cmd = $1;
			$msg->{userlogin} = $2;
			$msg->{userpass} = $3 if $3;
		}
		elsif($str =~ /^topic\b\s*(.*)/){
			$cmd = "command";
			$msg->{param1} = "topic";
			$msg->{param2} = $1 || "";
		}
		elsif($str =~ /^cast\s+(\w+)\s+(\w+)\s+(.*)/){
			$cmd = "cast";
			$msg->{param1} = $1;
			$msg->{param2} = $2;
			$msg->{param3} = $3;
		}
		elsif($str =~ /^reload\s*(.*)/){
			$cmd = "cast";
			$msg->{param1} = "exec";
			$msg->{param2} = 'mc.parse("/reload")';
			$msg->{param3} = $1 if $1;
		}
		elsif($str =~ /^info\b\s*(.*)/){
			$cmd = "command";
			$msg->{param1} = "info";
			$msg->{param2} = $1 || "";
		}
		else{
			$msg = "bad command: /$str";
		}
	}
	elsif($str){
		$cmd = "message";
		$msg->{text} = $str;
	}
	return ($cmd,$msg);
}
sub long_connection {
	my ($start,$end) = @_;
	if($main::debug){
		my $lc;
		if($end - $start > 30){
			$lc = ("*" x 40)."Super Very Long connect ".($end - $start)." ".("*" x 25)."\n";
		}
		elsif($end - $start > 10){
			$lc = ("*" x 30)."Very Long connect ".($end - $start)." ".("*" x 25)."\n";
		}
		elsif($end - $start > 2){
			$lc = ("*" x 20)."Long connect ".($end - $start)." ".("*" x 25)."\n";
		}
		if($lc){
			print $lc;
		}
	}
}
sub ts {
	return sprintf "%02d:%02d:%02d", (localtime)[2,1,0];
}
sub get_param {
	my $options = shift;
	local $SIG{__WARN__} = sub {die "GETOPT: ".join("\n",@_)};
	GetOptions(@$options) or die "$!";
}

sub process_response {
	my $msg = shift;
	if($msg->{type} eq "list"){
		print "LISTSIZE=",scalar(@{$msg->{list}})," rid=$msg->{rid}\n" if $main::debug;
		for(sort {$a->{ats} <=> $b->{ats}} @{$msg->{list}}){
			process_one_response($_);
		}
	}else{
		process_one_response($msg);
	}
}
sub process_one_response {
	my $msg = shift;
	if($msg->{type} eq "response"){
		if($msg->{error}){
			print "$msg->{ts} RESPONSE($msg->{command}:$msg->{rid}): error($msg->{error}): ",$msg->{text},"\n" if $main::debug || $main::response;
		}else{
			print "$msg->{ts} RESPONSE($msg->{command}:$msg->{rid}): ",$msg->{text},"\n" if $msg->{text} && $main::debug || $main::response;
		}
	}
	elsif($msg->{type} eq "message"){
		#utf8::decode($msg->{text});
		print ts(),"<",($_->{chanel}||""),"> ",($msg->{ts}||"")," [",($msg->{from}||""),":",($msg->{rid}||""),"] ",$msg->{text},"\n" unless $main::quiet;
	}
	elsif($msg->{type} eq "notice"){
		print ts(),"<",($msg->{chanel}||""),"> ",($msg->{ts}||"")," notice(",($msg->{level}||""),"): "
			,($msg->{param1}||""),"/"
			,($msg->{param2}||""),"/"
			,($msg->{param3}||""),"/"
			,($msg->{text}||"")
			,"\n" unless $main::quiet;
	}
}

sub _init {
	1 if $main::quiet && $main::login;
	1 if $main::sid;
	1 if $main::run;
}

1;
